// DemoDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Demo.h"
#include "DemoDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDemoDlg dialog

CDemoDlg::CDemoDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CDemoDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDemoDlg)
	m_Used = _T("");
	m_SN = _T("");
	m_COUNT = _T("");
	m_Hint = _T("");
	m_Block = 1;
	m_WriteBlock = 1;
	m_fpPin = 1;
	m_Pwidth5 = FALSE;
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	s_zkfp = _T("");
	sRegTemplate = _T("");
	sRegTemplate10 = _T("");
}

void CDemoDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDemoDlg)
	DDX_Control(pDX, IDC_ZKFPENGX2, zkfpEng);
	DDX_Text(pDX, IDC_EDUsed, m_Used);
	DDX_Text(pDX, IDC_EDSN, m_SN);
	DDX_Text(pDX, IDC_EDCount, m_COUNT);
	DDX_Text(pDX, IDC_EDHint, m_Hint);
	DDX_Text(pDX, IDC_EDIT_Block, m_Block);
	DDV_MinMaxInt(pDX, m_Block, 0, 63);
	DDX_Text(pDX, IDC_EDIT_WriteBlock, m_WriteBlock);
	DDV_MinMaxInt(pDX, m_WriteBlock, 1, 63);
	DDX_Text(pDX, IDC_EDIT_FINGERPIN, m_fpPin);
	DDX_Check(pDX, IDC_PINWIDE5, m_Pwidth5);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDemoDlg, CDialog)
	//{{AFX_MSG_MAP(CDemoDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTNInit, OnBTNInit)
	ON_BN_CLICKED(IDC_BTNSave, OnBTNSave)
	ON_BN_CLICKED(IDC_BTNReg, OnBTNReg)
	ON_BN_CLICKED(IDC_BTNIdentify, OnBTNIdentify)
	ON_BN_CLICKED(IDC_BTNVer, OnBTNVer)
	ON_WM_DESTROY()
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_BUTTON1, OnSetRFIDReaderAddr)
	ON_BN_CLICKED(IDC_BUTTON2, OnGetCardSN)
	ON_BN_CLICKED(IDC_BUTTON3, OnReadcard)
	ON_BN_CLICKED(IDC_BUTTON4, OnWriteCard)
	ON_BN_CLICKED(IDC_BUTTON5, OnTemplateToCard)
	ON_BN_CLICKED(IDC_BUTTON6, OnButton6)
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BTNRED, &CDemoDlg::OnBnClickedBtnred)
	ON_BN_CLICKED(IDC_BTNGREEN, &CDemoDlg::OnBnClickedBtngreen)
	ON_BN_CLICKED(IDC_BTNBEEP, &CDemoDlg::OnBnClickedBtnbeep)
	ON_BN_CLICKED(IDC_BTNWRITEPWD, &CDemoDlg::OnBnClickedBtnwritepwd)
	ON_BN_CLICKED(IDC_BTNREADPWD, &CDemoDlg::OnBnClickedBtnreadpwd)
	ON_BN_CLICKED(IDC_RADIO9, &CDemoDlg::OnBnClickedRadio9)
	ON_BN_CLICKED(IDC_RADIO10, &CDemoDlg::OnBnClickedRadio10)
	ON_BN_CLICKED(IDC_BTNDisConnect, &CDemoDlg::OnBnClickedBtndisconnect)
	ON_BN_CLICKED(IDC_BTNREGBYIMAGE, &CDemoDlg::OnBnClickedBtnregbyimage)
	ON_BN_CLICKED(IDC_BTNIDENBYIMAGE, &CDemoDlg::OnBnClickedBtnidenbyimage)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDemoDlg message handlers

BOOL CDemoDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	

	bPollCardOK = false;
	FingerCount = 1;
	fpcHandle = 0;

	CheckRadioButton(IDC_RADIOBMP, IDC_RADIOJPG, IDC_RADIOBMP);
	CheckRadioButton(IDC_RADIO9, IDC_RADIO10, IDC_RADIO9);
	enableButton(false);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CDemoDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CDemoDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CDemoDlg::OnBTNInit() 
{
	char buffer[10];
	
	if (zkfpEng.InitEngine() == 0)
	{
		enableButton(true);
		if (IsDlgButtonChecked(IDC_RADIO9) != 0)
			zkfpEng.put_FPEngineVersion("9");
		else
			zkfpEng.put_FPEngineVersion("10");
		fpcHandle = zkfpEng.CreateFPCacheDBEx();
		m_SN = zkfpEng.get_SensorSN();
		ltoa(zkfpEng.get_SensorIndex(), buffer, 10);
		m_Used = buffer;
		ltoa(zkfpEng.get_SensorCount(), buffer, 10);
		m_COUNT = buffer;
		SetDlgItemText(IDC_EDUsed, m_Used);
		SetDlgItemText(IDC_EDCount, m_COUNT);
		SetDlgItemText(IDC_EDSN, m_SN);		
		MessageBox("Initial Succeed");
	} 
	else
	{
		zkfpEng.EndEngine();
		MessageBox("Initial Failed");
	}
	FMatchType = 2;
}


BEGIN_EVENTSINK_MAP(CDemoDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CDemoDlg)
	ON_EVENT(CDemoDlg, IDC_ZKFPENGX2, 8 /* OnImageReceived */, OnOnImageReceivedZkfpengx2, VTS_PBOOL)
	ON_EVENT(CDemoDlg, IDC_ZKFPENGX2, 10 /* OnCapture */, OnOnCaptureZkfpengx2, VTS_BOOL VTS_VARIANT)
	ON_EVENT(CDemoDlg, IDC_ZKFPENGX2, 9 /* OnEnroll */, OnOnEnrollZkfpengx2, VTS_BOOL VTS_VARIANT)
	ON_EVENT(CDemoDlg, IDC_ZKFPENGX2, 5 /* OnFeatureInfo */, OnOnFeatureInfoZkfpengx2, VTS_I4)
	//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

void CDemoDlg::OnOnImageReceivedZkfpengx2(BOOL FAR* AImageValid) 
{
	// TODO: Add your control notification handler code here
	HDC hdc;

	hdc = this->GetDC()->m_hDC;

	zkfpEng.PrintImageAt(long(hdc), 330, 2, zkfpEng.get_ImageWidth(), zkfpEng.get_ImageHeight());
}

void CDemoDlg::OnBTNSave() 
{
	if (IsDlgButtonChecked(IDC_RADIOBMP) != 0)
		zkfpEng.SaveBitmap("fingerprint.bmp");
	else
		zkfpEng.SaveJPG("fingerprint.jpg");
	MessageBox("Fingerprint Image saved");
}

void CDemoDlg::OnBTNReg() 
{
	zkfpEng.CancelEnroll();
	zkfpEng.put_EnrollCount(3);
	zkfpEng.BeginEnroll();

	SetDlgItemText(IDC_EDHint, "start register");		
}

void CDemoDlg::OnBTNIdentify() 
{
	// TODO: Add your control notification handler code here
    if (zkfpEng.get_IsRegister())
        zkfpEng.CancelEnroll();
	SetDlgItemText(IDC_EDHint, "Identify(1:N)");		
    FMatchType = 2;	
}

void CDemoDlg::OnBTNVer() 
{
	// TODO: Add your control notification handler code here
    if (zkfpEng.get_IsRegister())
        zkfpEng.CancelEnroll();
	SetDlgItemText(IDC_EDHint, "Verify(1:1)");		
    FMatchType = 1;		
}

BOOL CDemoDlg::DestroyWindow() 
{
	return CDialog::DestroyWindow();
}

void CDemoDlg::OnOnCaptureZkfpengx2(BOOL ActionResult, const VARIANT FAR& ATemplate) 
{
	long id;
	long Score, ProcessNum;
	char buffer[80];
	CString sTemp;
	BOOL RegChanged;

	SetDlgItemText(IDC_EDHint, "Acquired Fingerprint template");		
	if (FMatchType == 1)
	{
		if(bPollCardOK)
		{
			BOOL ARegFeatureChanged;

			if(zkfpEng.VerRegFingerFile("fingerprint2.tpl",ATemplate,false,&ARegFeatureChanged))
			{
				SetDlgItemText(IDC_EDHint, "Verify Succeed(from Mifare Card)!");
			}
			else
			{
				SetDlgItemText(IDC_EDHint, "Verify Failed");
			}
			bPollCardOK = false;
		}
		else
		{
			sTemp = zkfpEng.GetTemplateAsString();
			BSTR bTemp;
			if (IsDlgButtonChecked(IDC_RADIO9) != 0)
			{
				bTemp = sRegTemplate.AllocSysString();
			}
			else
			{
				bTemp = sRegTemplate10.AllocSysString();
			}

			if (zkfpEng.VerFingerFromStr(&bTemp, (LPCTSTR)sTemp, FALSE, &RegChanged))
			{
				SetDlgItemText(IDC_EDHint, "Verify Succeed(from fingerprint reader)");
			}
			else
			{
				SetDlgItemText(IDC_EDHint, "Verify Failed");
			}
		}
	}	
	else if (FMatchType == 2) // 1:N
	{  
		Score = 8;
		id = zkfpEng.IdentificationInFPCacheDB(fpcHandle, ATemplate, &Score, &ProcessNum);
		if (id == -1)
		{
			SetDlgItemText(IDC_EDHint, "Identify Failed");
		}
		else
		{
			sprintf(buffer, "Identify Succeed ID = %d Score = %d  Processed Number = %d", id, Score, ProcessNum);
			SetDlgItemText(IDC_EDHint, buffer);
		}
	}   
}

void CDemoDlg::OnOnEnrollZkfpengx2(BOOL ActionResult, const VARIANT FAR& ATemplate) 
{
	VARIANT pTemplate;
	int ReturnValue;

	if (!ActionResult)
		MessageBox("Register Failed");
	else
	{
		// After enroll, you can get 9.0&10.0 template at the same time
		sRegTemplate = zkfpEng.GetTemplateAsStringEx("9");
		sRegTemplate10 = zkfpEng.GetTemplateAsStringEx("10");

		if(sRegTemplate.GetLength() > 0)
		{
			if(sRegTemplate10.GetLength() > 0)
				zkfpEng.AddRegTemplateStrToFPCacheDBEx(fpcHandle, FingerCount, (LPCTSTR)sRegTemplate, (LPCTSTR)sRegTemplate10);
			else
				MessageBox("Register 10.0 failed, template length is zero");

			pTemplate = zkfpEng.DecodeTemplate1((LPCTSTR)sRegTemplate);

			// Note: 10.0Template can not be compressed
			ReturnValue = zkfpEng.SetTemplateLen(&pTemplate, 602);
			zkfpEng.SaveTemplate("fingerprint.tpl", pTemplate);

			FingerCount = FingerCount + 1;
			UpdateData(TRUE);
			MessageBox("Register Succeed");
		}
		else
		{
			MessageBox("Register Failed, template length is zero");
		}
  }
}

void CDemoDlg::OnOnFeatureInfoZkfpengx2(long AQuality) 
{
	CString sTemp;
	char buffer[10];

	sTemp = "";
	if (zkfpEng.get_IsRegister())
	{
		ltoa(zkfpEng.get_EnrollIndex(), buffer, 10);
		sTemp = "Register Status: still press finger ";
		sTemp = sTemp + buffer + " times";
	}
	sTemp = sTemp + " Fingerprint quality";
	ltoa(zkfpEng.get_LastQuality(), buffer, 10);
	if (AQuality != 0)
		sTemp = sTemp + " not good, quality="  + buffer;
	else
		sTemp = sTemp +  " good, quality=" + buffer;
	SetDlgItemText(IDC_EDHint, sTemp);
}

void CDemoDlg::OnDestroy() 
{
	CDialog::OnDestroy();
}

void CDemoDlg::OnClose() 
{
	zkfpEng.EndEngine();
	if(fpcHandle > 0)
	{
		zkfpEng.FreeFPCacheDBEx(fpcHandle);
	}
	CDialog::OnClose();
}

/**
Get Reader Address and Serial number
*/
CString CDemoDlg::GetSnr()
{
	BYTE buf[128];
	memset(buf,1,128);
	int re = 0;
	if(zkfpEng.MF_GetSerNum(0, 0, buf))
	{
		CString str;
		str.Format("%02x %02x %02x %02x %02x %02x %02x %02x",
				buf[1],buf[2],buf[3],
				buf[4],buf[5],buf[6],buf[7],buf[8]);
		return str;
	}
	else
		return "";
}

void CDemoDlg::OnSetRFIDReaderAddr() 
{
	SetDlgItemText(IDC_EDHint, "Get Reader SN:" + GetSnr());	
}

int CDemoDlg::GetCardByteSerial(BYTE  *pSerial)
{
	BYTE buf[128];
	BYTE snr[16];
	memset(buf,0,128);
	memset(snr,0,16);

	if(!zkfpEng.MF_GET_SNR(0, 0, 0x26, 0x00, snr, buf))
		return 1;
	memcpy(pSerial, buf, 4);
	return 0;
}

/*
Get card serial number
*/
CString CDemoDlg::GetCardStrSerial()
{
	CString strre;
	BYTE buf[128];
	unsigned long nSerial;

	if(GetCardByteSerial(buf) == 0)
	{
		nSerial = ((buf[0] * 256 + buf[1])*256 + buf[2])* 256 +buf[3];

		if(nSerial > 0x7f000000)
			strre.Format("0x%02x%02x%02x%02x",buf[0],buf[1],buf[2],buf[3]);//,nSerial);
		else
			strre.Format("0x%02x%02x%02x%02x  : %d",buf[0],buf[1],buf[2],buf[3],nSerial);

		return strre;
	}
	return "";
}

void CDemoDlg::OnGetCardSN() 
{
	SetDlgItemText(IDC_EDHint, "Get Card SN:" + GetCardStrSerial());	
}

int CDemoDlg::ReadBLOCK(int blockIndex, BYTE *pData, unsigned char *key)
{
	BYTE dataBuf[1024];
	BYTE len;

	if(blockIndex<0 || blockIndex>63)// mifare s50card 0~63
		return 10;
	int result = 0;
	memset(dataBuf, 0, 1024);
	len = 1;

	if(!zkfpEng.MF_PCDRead(0 ,0, 0, blockIndex, len, key, dataBuf))
		return 1;
	memcpy(pData, dataBuf, 16);
	return 0;
}

int CDemoDlg::ReadBlock2(BYTE blockIndex, int mod, BYTE *pData, int blockLen)
{
	BYTE *buf;
	BYTE pKey[6];

	BYTE nAdd,BlockNum;
	int i,result = 0;

	nAdd = blockIndex;
	buf = pData;

	for(i = 0;i< blockLen;)
	{
		// S50 Card：1024Bytes，16 Sectors，each sector 4 blocks
		// S70 Card：4096Bytes，40 Sectors，the first 32 secotrs have per4 block，last 8 have per16 blocks.
		if(nAdd >= 64)
			return -1;

		if(nAdd == 0) // In first secotr, block 0 for card number... Only 2 block can use.
		{	
			nAdd = 1;
			BlockNum = 2;
		}
		else if(nAdd<32 *4) // s50 card
		{	
			if(nAdd%4 == 3)
				nAdd++;
			BlockNum = 3;
		}
		else if(nAdd> 32*4) // s70 card
		{	
			if(nAdd%16 == 15)	
				nAdd++;
			BlockNum = 3;
		}

		memset(pKey, 0xFF, 6); // As 0xffffffffffff for keyA
		
		if(!zkfpEng.MF_PCDRead(0, 0, 0, nAdd, BlockNum, pKey, buf))
			return 1;

		nAdd += BlockNum;
		buf = buf + 16*BlockNum;
		i += BlockNum;
	}
	return 0;
}

int CDemoDlg::WriteBLOCK(BYTE blockIndex, BYTE *pData, unsigned char *key)
{
	int result = 0;

	if(blockIndex<0 || blockIndex>64) // mifare s50card 0~63 
		return 10;
	if(blockIndex%4 == 3)	// Note, it's password block
		return 11;

	if(!zkfpEng.MF_PCDWrite(0, 0, 0, blockIndex, 1, key, pData))
		return 1;
	return 0;
}

int CDemoDlg::WriteBlock2(BYTE blkIndex, int mod, BYTE *pData, int blockLen)
{
	BYTE *buf;
	BYTE pKey[6];

	BYTE nAdd, BlockNum;
	int i, result = 0;

	nAdd = blkIndex;
	
	buf = pData;

	for(i = 0; i< blockLen;) 
	{
		// S50 Card：1024Bytes，16 Sectors，each sector 4 blocks
		// S70 Card：4096Bytes，40 Sectors，the first 32 secotrs have per4 block，last 8 have per16 blocks.
		if(nAdd >= 64)
			return -1;

		if(nAdd==0) // In first secotr, block 0 for card number... Only 2 block can use.
		{	
			nAdd=1;
			BlockNum = 2;
		}
		else if(nAdd<32 *4) // s50 card
		{	
			if(nAdd%4 == 3)
				nAdd++;
			BlockNum = 3;
		}
		else if(nAdd> 32*4) // s70 card
		{	
			if(nAdd%16 == 15)
				nAdd++;
			BlockNum = 3;
		}

		memset(pKey, 0xff, 6); //0xffffffffffff as keyA

		if(!zkfpEng.MF_PCDWrite(0, 0, 0, nAdd, BlockNum, pKey, buf))
		{
				return 1;
		}
		nAdd += BlockNum;
		buf = buf + 16*BlockNum;
		i += BlockNum;
	}
	return 0;
}

void CDemoDlg::OnReadcard() 
{
	CString temp;
	BYTE buf[256];
	BYTE key[6];
	int Result,Block;

	UpdateData(TRUE);
	Block = m_Block;
	memset(key, 0xFF, 6); // 0xFFFFFFFFFFFF as keyA
	Result =  ReadBLOCK(Block, buf, key);
	if(Result == 0)
		temp.Format("BLOCK = 0x%02x, Data=0x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ",
				Block,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],
				buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]);
	else
		temp.Format("Errorcode = %x", Result);
	SetDlgItemText(IDC_EDHint, "Read card:" + temp);	
}

void CDemoDlg::OnWriteCard() 
{
	CString temp;
	BYTE buf[16];
	BYTE key[6];
	int Result,Block;

	UpdateData(TRUE);
	if(m_WriteBlock%4 ==3 || m_WriteBlock == 0)
	{
		MessageBox("parameter error!");
		m_WriteBlock = 1;
		UpdateData(FALSE);
		
	}
	Block = m_WriteBlock;
	memset(buf, 0x66, 6);
	// FF 07 80 69 as default
	buf[6] = 0xFF;
	buf[7] = 0x07;
	buf[8] = 0x80;
	buf[9] = 0x69;
	memset(&buf[10], 0xFF, 6);

	memset(key, 0xFF, 6); // 0xFFFFFFFFFFFF as keyA
	Result =  WriteBLOCK(Block, buf, key);
	if(Result == 0)
		temp.Format("BLOCK = 0x%02x, success ",Block);
	else
		temp.Format("Errorcode = %x", Result);
	SetDlgItemText(IDC_EDHint, "Write card:" + temp);	
}

void CDemoDlg::OnTemplateToCard() 
{
		CString temp;
		int Result, DataLen, blockLen;
		BYTE buf[2000];
		BYTE buf2[2024];
		FILE *fp;

		UpdateData(TRUE);
		// Get Reader Address and Serial number
		temp = GetSnr();
		if(temp == "")
		{
			MessageBox("cardmodule fault!");
			return;
		}

		// Get card serial number
		temp = GetCardStrSerial();
		if(temp == "")
		{
			MessageBox("no card or card error!");
			return;
		}

		// Save fingerprint.tpl to card
		DataLen = 0;
		if(!(fp = fopen("fingerprint.tpl", "rb")) || !FingerCount)
		{
			 MessageBox("please register finger first!");
			 return;
		}
		fseek(fp, 0, SEEK_SET);
		// A template is not more than 2000 Bytes
		DataLen =  fread( (void *)buf, sizeof(unsigned char), 2000, fp);
		fclose(fp);	

		// Content structure
		// mark(2B) + UserID(2B/4B)+TemplateSize(2B)+FingerIndex[2B]+Template
		if(!m_Pwidth5) // 9 PinWidth
		{
			// mark
			buf2[0] = 'Z'+16;
			buf2[1] = 1;

			// UserID
			memcpy(&buf2[2],(void *)&m_fpPin, 4);

			// Template size
			buf2[6] = DataLen%256;
			buf2[7] = DataLen/256;
			
			// FingerIndex
			buf2[8] = 0x0f;
			buf2[9] = 0xff;

			// Template
			memcpy(&buf2[10], buf, DataLen);

			//从块0开始写起，
			DataLen += 10; 
			if(DataLen > 16*3*16 -16)	//s50卡最多保存16*3*16 -16个字节
				DataLen = 16*3*16 -16; 
		}
		else  // 5 PinWidth
		{
			// mark
			buf2[0] = 'Z'+16;
			buf2[1] = 1;

			// UserID
			memcpy(&buf2[2], (void *)&m_fpPin, 2);

			// Template size
			buf2[4] = DataLen%256;//4.5
			buf2[5] = DataLen/256;//
			
			// Fingerindex
			buf2[6] = 0x0f;
			buf2[7] = 0xff;

			// Template
			memcpy(&buf2[8], buf, DataLen);

			DataLen += 8;
			if(DataLen > 16*3*16 -16)
				DataLen = 16*3*16 -16; 
		}

		blockLen = DataLen/16;
		if((DataLen % 16) > 0)
			blockLen += 1;
 		Result = WriteBlock2(0, 0, buf2, blockLen);

		if(Result != 0)
		{
			MessageBox("write card error!");
		}
		else
		{
			MessageBox("write card sucess!");
		}
}



void CDemoDlg::OnButton6() 
{
	int Result, DataLen;
	long Score;
	long ProcessedFPNumber;
	FILE *fp;

	BYTE buf[2000] = {0};
	BYTE buf2[2024] = {0};
	UpdateData(TRUE);
	
	Result = ReadBlock2(0, 0, buf2, 608/16); // not more than 608 bytes

	if(Result != 0)
	{
		MessageBox("read card error,please put card and operate it once again!");
		return;
	}

	// Content structure
	// mark(2B) + UserID(2B/4B)+TemplateSize(2B)+FingerIndex[2B]+Template

	if(buf2[0] != 'Z'+16  && buf2[1] != 1)
	{
		MessageBox("not fingertemplate card");
		return;		
	}

	if(!m_Pwidth5) // 9 PinWidth
	{
		// UserID
		memcpy((void *)&m_fpPin,&buf2[2], 4);
		
		// Templaet size
		DataLen = buf2[6] + buf2[7] *256;
		
		// fingerIndex.
		//buf2[8] ;
		//buf2[9] ;

		if(DataLen > 752-16) //s50 valid capacity not more than 752bytes(16*3*16-16)
		{
			 MessageBox("Fingertemplate abnormal, its length is larger than 752 bytes");
			 return;
		}
		memcpy(buf, &buf2[10], DataLen);
	}
	else // 5 PinWidth
	{
		// UserID
		memcpy((void *)&m_fpPin, &buf2[2], 2);
		
		// Template size
		DataLen = buf2[4] + buf2[5] *256;
		
		// fingerIndex
		//buf2[6] ;
		//buf2[7] ;

		if(DataLen > 752-16)
		{
			 MessageBox("Fingertemplate abnormal, its length is larger than 752 bytes");
			 return;
		}	
		memcpy(buf, &buf2[8], DataLen);
	}

	// Save template to file
	if(!(fp = fopen("fingerprint2.tpl", "wb")))
	{
		MessageBox("write fingertemplate file fail!");
		return;
	}
	fseek(fp, 0, SEEK_SET);
	DataLen = fwrite( (void *)buf, sizeof(unsigned char), DataLen, fp);
	fclose(fp);	

	Score = 8;
	ProcessedFPNumber = 1;

	if(FMatchType == 2)
	{
		Result = zkfpEng.IdentificationFromFileInFPCacheDB(fpcHandle, "fingerprint2.tpl", &Score, &ProcessedFPNumber);
		if(Result == -1)
		{	
			MessageBox("identificate error!");
			return ;
		}
		else
		{
			CString str;
			str.Format("Identify Succeed ID = %d Score = %d  Processed Number = %d", Result, Score, ProcessedFPNumber);
			MessageBox(str);
		}
	}
	else
	{
		CString str;

		str.Format("sucess，USER PIN = %d please press finger!", m_fpPin);

		FMatchType = 1;
		MessageBox(str);
		bPollCardOK = true;
	}
	UpdateData(FALSE);
}


/*
ControlSensor(ACode As Long; AValue As Long)
If ACode=11, control the green light, if it’s 12, control the red light, if it’s 13,
control the beep.
If AValue=1, lights on, if it’s 0, lights off.
*/
void CDemoDlg::OnBnClickedBtnred()
{
	zkfpEng.ControlSensor(12, 1);
	zkfpEng.ControlSensor(12, 0);
}

void CDemoDlg::OnBnClickedBtngreen()
{
	zkfpEng.ControlSensor(11, 1);
	zkfpEng.ControlSensor(11, 0);
}

void CDemoDlg::OnBnClickedBtnbeep()
{
	zkfpEng.ControlSensor(13, 1);
	zkfpEng.ControlSensor(13, 0);
}

void CDemoDlg::OnBnClickedBtnwritepwd()
{
	CString temp;
	BYTE buf[16];
	BYTE key[6];
	int Result;

	// keyA
	memset(buf, 0x66, 6);
	// FF 07 80 69 as default
	buf[6] = 0xFF;
	buf[7] = 0x07;
	buf[8] = 0x80;
	buf[9] = 0x69;

	// keyB
	memset(&buf[10], 0xFF, 6);

	memset(key, 0xFF, 6); // 0xFFFFFFFFFFFF as keyA	

	// Here we only modify the first sector's keyA
	if(zkfpEng.MF_PCDWrite(0, 0, 0, 3, 1, key, buf))
	{
		temp.Format("BLOCK = 0x%02x, success ", 3);
	}
	else
		temp.Format("Errorcode = %x", buf[0]);
	SetDlgItemText(IDC_EDHint, "Write card:" +  temp);
}

void CDemoDlg::OnBnClickedBtnreadpwd()
{
	CString temp;
	BYTE buf[256];
	BYTE key[6];
	int Result,Block;

	UpdateData(TRUE);
	Block = m_Block;

	memset(key, 0x66, 6); // 0xFFFFFFFFFFFF as keyA
	Result =  ReadBLOCK(Block, buf, key);
	if(Result == 0)
		temp.Format("BLOCK = 0x%02x, Data=0x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ",
				Block,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],
				buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]);
	else
		temp.Format("Errorcode = %x", Result);
	SetDlgItemText(IDC_EDHint, "Read card:" + temp);
}

void CDemoDlg::OnBnClickedRadio9()
{
	zkfpEng.put_FPEngineVersion("9");
}

void CDemoDlg::OnBnClickedRadio10()
{
	zkfpEng.put_FPEngineVersion("10");
}

void CDemoDlg::enableButton(bool bEnable)
{
	GetDlgItem(IDC_BTNInit)->EnableWindow(!bEnable);
	GetDlgItem(IDC_BTNDisConnect)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNSave)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNReg)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNVer)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNIdentify)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNRED)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNGREEN)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNBEEP)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON5)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON1)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON6)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON2)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON3)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON4)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNREADPWD)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNWRITEPWD)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNREGBYIMAGE)->EnableWindow(bEnable);
	GetDlgItem(IDC_BTNIDENBYIMAGE)->EnableWindow(bEnable);
}
void CDemoDlg::OnBnClickedBtndisconnect()
{
	zkfpEng.EndEngine();
	enableButton(false);
}

void CDemoDlg::OnBnClickedBtnregbyimage()
{
	LPCTSTR lpszFilter = _T("BMP File(*.bmp)|*.bmp|JPG File(*.jpg)|*.jpg|");
	CFileDialog dlg1(TRUE,lpszFilter,NULL,OFN_HIDEREADONLY|
		OFN_OVERWRITEPROMPT,lpszFilter,NULL);
	CString filename;
	CFile file;
	if (dlg1.DoModal() == IDOK)
	{
		filename = dlg1.GetPathName();
		if(zkfpEng.get_IsRegister())
			zkfpEng.CancelEnroll();
		zkfpEng.put_EnrollCount(1);
		zkfpEng.BeginEnroll();
		if(!zkfpEng.AddImageFile((LPCTSTR)filename, 500))
		{
			MessageBox(_T("Extract failed or not using the standard version of ZKFinger SDK"));
		}
	}
}

void CDemoDlg::OnBnClickedBtnidenbyimage()
{
	LPCTSTR lpszFilter = _T("BMP File(*.bmp)|*.bmp|JPG File(*.jpg)|*.jpg|");
	CFileDialog dlg1(TRUE,lpszFilter,NULL,OFN_HIDEREADONLY|
		OFN_OVERWRITEPROMPT,lpszFilter,NULL);
	CString filename;
	CFile file;
	if (dlg1.DoModal() == IDOK)
	{
		filename = dlg1.GetPathName();
		if(zkfpEng.get_IsRegister())
			zkfpEng.CancelEnroll();

		zkfpEng.BeginCapture();

		if(!zkfpEng.AddImageFile((LPCTSTR)filename, 500))
		{
			MessageBox(_T("Extract failed or not using the standard version of ZKFinger SDK"));
		}
	}
}
